﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Network;
using Rappelz.GameServer.Database;

namespace Rappelz.GameServer
{
    public class MixBase
    {
        public class MaterialInfo
        {
            public const int MATERIAL_INFO_COUNT = 5;
            public int[] type = new int[MATERIAL_INFO_COUNT];
            public int[] value = new int[MATERIAL_INFO_COUNT];
        }

        public enum CheckType : int
        {
            ItemGroup = 1,
            ItemClass = 2,
            ItemId = 3,
            ItemRank = 4,
            ItemLevel = 5,
            FlagOn = 6,
            FlagOff = 7,
            EnhanceMatch = 8,
            EnhanceMismatch = 9,
            ItemCount = 10,
            ElementalEffectMatch = 11,
            ElementalEffectMismatch = 12,
            ItemWearPositionMatch = 13,
            ItemWearPositionMismatch = 14,
        }

        public enum MixType : int
        {
            Enhance = 101,
            EnhanceSkillCard = 102,
            EnhanceWithoutFail = 103,
            Unk1 = 104,
            Unk2 = 105,
            SetLevel = 201,
            SetLevelCreateItem = 202,
            SelLevelSetFlag = 211,
            SetLevelSetFlagCreateItem = 212,
            Unk3 = 214,
            Unk4 = 215,
            AddLevel = 301,
            AddLevelCreateItem = 302,
            AddLevelSetFlag = 311,
            AddLevelSetFlagCreateItem = 312,
            Recycle = 401,
            RecycleEnhance = 402,
            RestoreEnhanceSetFlag = 501,
            CreateItem = 601,
            SetElementalEffect = 701,
            SetElementalEffectParameter = 702,
            Unk5 = 703,
            Unk6 = 803,
            Unk7 = 804,
            Unk8 = 805,
            Unk9 = 806,
        }

        public const int VALUE_COUNT = 6;
        public const int MAX_SUB_MATERIAL_COUNT = 9;

        public int id;                                                                  // 0x0
        public int type;                                                                // 0x4
        public int[] value = new int[VALUE_COUNT];                                      // 0x8
        public int sub_material_cnt;                                                    // 0x20
        public MaterialInfo main_material = new MaterialInfo();                         // 0x24
        public MaterialInfo[] sub_material = new MaterialInfo[MAX_SUB_MATERIAL_COUNT];  // 0x4C
    }

    public class EnhanceInfo
    {
        public int nSID;
        public uint Flag;
        public int nRank;
        public int nFailResult;
        public int nMaxEnhance;
        public uint nLocalFlag;
        public int nNeedItemCode;
        public float[] fPercentage = new float[20];

        // Enum           :   <unnamed-tag>, Type: int
        // Data           :     constant 0x0, Constant, Type: int, EF_WEAPON
        // Data           :     constant 0x1, Constant, Type: int, EF_ARMOR
        // Data           :     constant 0x2, Constant, Type: int, EF_SHIELD
        // Data           :     constant 0x3, Constant, Type: int, EF_HELM
        // Data           :     constant 0x4, Constant, Type: int, EF_GLOVE
        // Data           :     constant 0x5, Constant, Type: int, EF_BOOTS
        // Data           :     constant 0x6, Constant, Type: int, EF_BELT
        // Data           :     constant 0x7, Constant, Type: int, EF_MANTLE
        // Data           :     constant 0x8, Constant, Type: int, EF_ACCESSORY
        // Data           :     constant 0x9, Constant, Type: int, EF_SKILL
        // Data           :   this+0x4, Member, Type: struct XFlag<int,1>, Flag
        // UserDefinedType:     XFlag<int,1>
        // 
        // Enum           :   <unnamed-tag>, Type: int
        // Data           :     constant 0x1, Constant, Type: int, RESULT_FAIL
        // Data           :     constant 0x2, Constant, Type: int, RESULT_SKILL_CARD_FAIL
        // Data           :     constant 0x3, Constant, Type: int, RESULT_ACCESSORY_FAIL
        // Function       :   public void EnhanceInfo::EnhanceInfo(const struct EnhanceInfo &)
        // Function       :   public void EnhanceInfo::EnhanceInfo()
        // Function       :   public struct EnhanceInfo & EnhanceInfo::operator=(const struct EnhanceInfo &)

    }

    public class MixManager
    {
        public static List<MixBase> s_vMixInfo = new List<MixBase>();
        public static List<EnhanceInfo> s_vEnhanceInfo = new List<EnhanceInfo>();

// UserDefinedType: MixManager
        public static void RegisterEnhanceInfo(EnhanceInfo info)
        {
            foreach (EnhanceInfo ei in s_vEnhanceInfo)
            {
                if (ei.nSID == info.nSID)
                    return;
            }
            s_vEnhanceInfo.Add(info);
        }

        public static bool EnhanceItem(MixBase pMixInfo, Player pPlayer, Item pMainMaterial, int nSubMaterialCount, Item[] pSubMaterial, ushort[] pCountList)
        {
// .text:00537882 pMixInfo         = dword ptr 104  68h
// .text:00537882 pMainMaterial    = dword ptr 112  70h
// .text:00537882 pPlayer         = dword ptr  108  6Ch
// .text:00537882 nSubMaterialCount= dword ptr 116  74h
// .text:00537882 pSubMaterial    = dword ptr  120  78h
// .text:00537882 pCountList      = dword ptr  124  7Ch

            EnhanceInfo pInfo;              // -24  -18h
            int nCurrentEnhance;            // 28   1Ch
            int itemEnhance;                // 68   44h
            Item pCube = null;              // 68   44h
            uint nRandom;                   // 84   54h
            string szRes;                   // 76   4Ch
            Item pPowder = null;            // 112  70h
            bool bResult;                   // 115  73h
            uint tmp;                       // 112  70h

            nCurrentEnhance = pMainMaterial.m_Instance.nEnhance;
            pInfo = getEnhanceInfo(pMixInfo.value[0]);

            if (pInfo == null)
            {
                Messages.SendResult(pPlayer, 256, 28, 0);
                return false;
            }

            foreach (Item ti in pSubMaterial)
            {
                if(ti != null && ti.m_Instance.Code == pInfo.nNeedItemCode)
                {
                    pCube = ti;
                    break;
                }
            }

            pPowder = null;
            if (pMixInfo.type == 103 )
            {
                if (pSubMaterial[0] != null && pSubMaterial[0].m_pItemBase.nType == 4)
                {
                    pPowder = pSubMaterial[1];
                }
                else
                {
                    pPowder = pSubMaterial[0];
                    pCube = pSubMaterial[1];
                }
            }
            if (pCube == null
              || pCube.m_Instance.Code != pInfo.nNeedItemCode
              || pMixInfo.type == 103 && pPowder == null
              || pInfo.nMaxEnhance <= pMainMaterial.m_Instance.nEnhance)
            {
                Messages.SendResult(pPlayer, 256, 28, 0);
                return false;
            }

            if (pMixInfo.type == 103)
            {
                ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pPowder.m_Instance.nLevel + 100 * pPowder.m_Instance.nEnhance,
                    pPowder.m_Instance.Code,1,pPowder.m_Instance.nCount-1,pMixInfo.id,0,0,0,pPowder.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","EITEM");
            }
            ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pCube.m_Instance.nLevel + 100 * pCube.m_Instance.nEnhance,
                pCube.m_Instance.Code, 1, pCube.m_Instance.nCount - 1, pMixInfo.id, 0, 0, 0, pCube.m_Instance.UID, pPlayer.GetAccountName(), pPlayer.GetName(), "", "EITEM");

            ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pMainMaterial.m_Instance.nLevel + 100 * pMainMaterial.m_Instance.nEnhance,
                pMainMaterial.m_Instance.Code,1,pMainMaterial.m_Instance.nCount,pMainMaterial.m_Instance.nLevel,0,0,0,pMainMaterial.m_Instance.UID,
                pPlayer.GetAccountName(),pPlayer.GetName(),"","EITEM");

//            pPlayer.EraseItem(pCube, 1);
            if (pMixInfo.type == 103 && pPowder != null)
                pPlayer.EraseItem(pPowder, 1);

            if (pMixInfo.type == 101)
                itemEnhance = Globals.GetRandomInt32(pMixInfo.value[1], pMixInfo.value[2]);
            else
                itemEnhance = 1;

            nRandom = (uint)(pInfo.fPercentage[nCurrentEnhance] * 100000.0f);
            bResult = false;
            szRes = "FAIL";
            if (pPlayer.m_nPermission > 0)
                nRandom += 100000;
            if (Globals.GetRandomInt32(0, 100000) > nRandom)
            {
                // failed
                if (pMixInfo.type != 103 )
                {
                    procEnhanceFail(pPlayer, pMainMaterial, pInfo.nFailResult);
                    Messages.SendMixResult(pPlayer, null, 0);
                }
                else
                {
                    if (GameRule.nEnhanceFailType == 0)
                    {
                        pMainMaterial.m_Instance.nEnhance = ((Globals.GetRandomInt32(nCurrentEnhance * pMixInfo.value[1], nCurrentEnhance * pMixInfo.value[2]) / 1000) + 5) / 10;
                    }
                    else if (GameRule.nEnhanceFailType == 1)
                    {
                        pMainMaterial.m_Instance.nEnhance = nCurrentEnhance - 1;
                    }
                    pMainMaterial.m_bIsNeedUpdateToDB = true;
                    Messages.SendItemMessage(pPlayer, pMainMaterial);
                    Messages.SendMixResult(pPlayer, null, 0);
                }
            }
            else
            {
                // successful
                pMainMaterial.m_Instance.nEnhance = nCurrentEnhance + itemEnhance;
                pMainMaterial.m_bIsNeedUpdateToDB = true;
                Messages.SendItemMessage(pPlayer, pMainMaterial);
                uint[] handles = new uint[1];
                handles[0] = pMainMaterial.m_hHandle;
                Messages.SendMixResult(pPlayer, handles, 1);
                szRes = "SUCS";
                bResult = true;
            }

            pMainMaterial.m_bIsNeedUpdateToDB = true;
            pMainMaterial.DBQuery(new DB_UpdateItem(pMainMaterial));

            ServerLog.Log((ushort)0x96A, pPlayer.GetAccountID(), pPlayer.GetSID(), pMainMaterial.m_Instance.nLevel + 100 * pMainMaterial.m_Instance.nEnhance,
                pMainMaterial.m_Instance.Code, 1, pMixInfo.id, 0, 0, 0, 0, pMainMaterial.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"",szRes);
            return bResult;
        }

        public static bool EnhanceSkillCard(MixBase pMixInfo, Player pPlayer, Item pMainMaterial, int nSubMaterialCount, ref Item[] pSubMaterial, ref ushort[] pCountList)
        {
// .text:00537E99 nSubMaterialCount= dword ptr  16  10h
// .text:00537E99 pMixInfo        = dword ptr   104 68h
// .text:00537E99 pPlayer         = dword ptr   108 6Ch
// .text:00537E99 pMainMaterial   = dword ptr   112 70h
// .text:00537E99 nSubMaterialCount= dword ptr  116 74h
// .text:00537E99 pSubMaterial    = dword ptr   120 78h
// .text:00537E99 pCountList      = dword ptr   124 7Ch
            Item pSkillCard2 = null;                    // -16  -10h
            Item pSkillCard1 = null;
            Item pCube = null;                          // 84   54h
            bool bResult = false;                       // 116  74h
            uint nRandom = 0;                           // 84   54h
            EnhanceInfo pInfo = null;                   // 0    0h
            uint tmp = 0;                               // 0    0h
            int i;

            if (nSubMaterialCount <= 0)
            {
                Messages.SendResult(pPlayer, 256, 28, 0);
                return false;
            }

            for(i = 0; i < nSubMaterialCount; ++i)
            {
                if (pSubMaterial[i].m_pItemBase.nGroup == 23)
                {
                    pCube = pSubMaterial[i];
                }
                else
                {
                    if (pSkillCard1 != null)
                    {
                        if (pSubMaterial[i].m_pItemBase.nGroup == 10 )
                            pSkillCard2 = pSubMaterial[i];
                    }
                    else
                    {
                        if (pSubMaterial[i].m_pItemBase.nGroup == 10 )
                            pSkillCard1 = pSubMaterial[i];
                    }
                }
            }
            pInfo = getEnhanceInfo(pMixInfo.value[0]);
            if (pCube != null
              && pSkillCard1 != null
              && pSkillCard2 != null
              && pSkillCard1.m_pItemBase.nSkillID == pSkillCard2.m_pItemBase.nSkillID
              && pSkillCard1.m_Instance.nEnhance == pSkillCard2.m_Instance.nEnhance
              && pInfo != null
              && pInfo.nNeedItemCode == pCube.m_Instance.Code
              && pInfo.nMaxEnhance > pSkillCard1.m_Instance.nEnhance)
            {
                ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pCube.m_Instance.nLevel + 100 * pCube.m_Instance.nEnhance,
                    pCube.m_Instance.Code,1,pCube.m_Instance.nCount-1,pMixInfo.id,0,0,0,pCube.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","ESKILL");
                ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pSkillCard1.m_Instance.nLevel + 100 * pSkillCard1.m_Instance.nEnhance,
                    pSkillCard1.m_Instance.Code,1,pSkillCard1.m_Instance.nCount-1,pMixInfo.id,0,0,0,pSkillCard1.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","ESKILL");
                ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pSkillCard2.m_Instance.nLevel + 100 * pSkillCard2.m_Instance.nEnhance,
                    pSkillCard2.m_Instance.Code,1,pSkillCard2.m_Instance.nCount-1,pMixInfo.id,0,0,0,pSkillCard2.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","ESKILL");

//                pPlayer.EraseItem(pCube,1);
//                pPlayer.EraseItem(pSkillCard2,1);

                nRandom = (uint)(pInfo.fPercentage[pSkillCard1.m_Instance.nEnhance]*10000);
                bResult = false;
                if (Globals.GetRandomInt32(0, 100000) > nRandom)
                {
                    ServerLog.Log((ushort)0x96A,pPlayer.GetAccountID(),pPlayer.GetSID(),pSkillCard1.m_Instance.nLevel + 100 * pSkillCard1.m_Instance.nEnhance,
                        pSkillCard1.m_Instance.Code,1,pMixInfo.id,0,0,0,0,pSkillCard1.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","FAIL");
                    procEnhanceFail(pPlayer, pSkillCard1, pInfo.nFailResult);
                    Messages.SendMixResult(pPlayer, null, 0);
                }
                else
                {
                    pSkillCard1.m_Instance.nEnhance++;
                    pSkillCard1.m_bIsNeedUpdateToDB = true;
                    Messages.SendItemMessage(pPlayer, pSkillCard1);
                    uint[] handles = new uint[1];
                    handles[0] = pSkillCard1.m_hHandle;

                    Messages.SendMixResult(pPlayer, handles, 1);
                    bResult = true;
                    pSkillCard1.DBQuery(new DB_UpdateItem(pSkillCard1));
                    ServerLog.Log((ushort)0x96A,pPlayer.GetAccountID(),pPlayer.GetSID(),pSkillCard1.m_Instance.nLevel + 100 * pSkillCard1.m_Instance.nEnhance,
                        pSkillCard1.m_Instance.Code,1,pMixInfo.id,0,0,0,0,pSkillCard1.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","SUCS");
                }
            }
            else
            {
                Messages.SendResult(pPlayer, 256, 28, 0);
                return false;
            }
            return bResult;
        }

        public static bool EnhanceSummon(MixBase pMixInfo, Player pPlayer, Item pMainMaterial, int nSubMaterialCount, ref Item[] pSubMaterial, ref ushort[] pCountList)
        {
            // .text:00537E99 nSubMaterialCount= dword ptr  16  10h
            // .text:00537E99 pMixInfo        = dword ptr   104 68h
            // .text:00537E99 pPlayer         = dword ptr   108 6Ch
            // .text:00537E99 pMainMaterial   = dword ptr   112 70h
            // .text:00537E99 nSubMaterialCount= dword ptr  116 74h
            // .text:00537E99 pSubMaterial    = dword ptr   120 78h
            // .text:00537E99 pCountList      = dword ptr   124 7Ch
            Item pSubCard = null;                    // -16  -10h
            Item pMainCard = null;
            Item pCat = null;                          // 84   54h
            bool bResult = false;                       // 116  74h
            uint nRandom = 0;                           // 84   54h
            EnhanceInfo pInfo = null;                   // 0    0h
            uint tmp = 0;                               // 0    0h
            int i;

            if (nSubMaterialCount <= 0)
            {
                Messages.SendResult(pPlayer, 256, 28, 0);
                return false;
            }

            pMainCard = pMainMaterial;

            for (i = 0; i < nSubMaterialCount; ++i)
            {
                if (pSubMaterial[i].m_pItemBase.nGroup == 0)
                {
                    pCat = pSubMaterial[i];
                }
                else if (pSubMaterial[i].m_pItemBase.nGroup == 13)
                {
                      pSubCard = pSubMaterial[i];
                }
            }

            pInfo = getEnhanceInfo(pMixInfo.value[0]);

            if (pCat != null
              && pMainCard != null
              && pSubCard != null
              && pMainCard.m_pItemBase.nCode == pSubCard.m_pItemBase.nCode
              && pMainCard.m_Instance.nEnhance == pSubCard.m_Instance.nEnhance
              && pInfo != null
              && pInfo.nNeedItemCode == pCat.m_Instance.Code
              && pInfo.nMaxEnhance > pMainCard.m_Instance.nEnhance)
            {
                ServerLog.Log((ushort)0x969, pPlayer.GetAccountID(), pPlayer.GetSID(), pCat.m_Instance.nLevel + 100 * pCat.m_Instance.nEnhance,
                    pCat.m_Instance.Code, 1, pCat.m_Instance.nCount - 1, pMixInfo.id, 0, 0, 0, pCat.m_Instance.UID, pPlayer.GetAccountName(), pPlayer.GetName(), "", "ESKILL");
                ServerLog.Log((ushort)0x969, pPlayer.GetAccountID(), pPlayer.GetSID(), pMainCard.m_Instance.nLevel + 100 * pMainCard.m_Instance.nEnhance,
                    pMainCard.m_Instance.Code, 1, pMainCard.m_Instance.nCount - 1, pMixInfo.id, 0, 0, 0, pMainCard.m_Instance.UID, pPlayer.GetAccountName(), pPlayer.GetName(), "", "ESKILL");
                ServerLog.Log((ushort)0x969, pPlayer.GetAccountID(), pPlayer.GetSID(), pSubCard.m_Instance.nLevel + 100 * pSubCard.m_Instance.nEnhance,
                    pSubCard.m_Instance.Code, 1, pSubCard.m_Instance.nCount - 1, pMixInfo.id, 0, 0, 0, pSubCard.m_Instance.UID, pPlayer.GetAccountName(), pPlayer.GetName(), "", "ESKILL");

                pPlayer.EraseItem(pCat,1);
                pPlayer.EraseSummon(pSubCard.m_pSummon);
                pPlayer.EraseItem(pSubCard,1);

                nRandom = (uint)(pInfo.fPercentage[pMainCard.m_Instance.nEnhance] * 10000);
                bResult = false;
                if (Globals.GetRandomInt32(0, 100000) > nRandom && pPlayer.m_nPermission != 100)
                {
                    ServerLog.Log((ushort)0x96A, pPlayer.GetAccountID(), pPlayer.GetSID(), pMainCard.m_Instance.nLevel + 100 * pMainCard.m_Instance.nEnhance,
                        pMainCard.m_Instance.Code, 1, pMixInfo.id, 0, 0, 0, 0, pMainCard.m_Instance.UID, pPlayer.GetAccountName(), pPlayer.GetName(), "", "FAIL");
                    procEnhanceFail(pPlayer, pSubCard, pInfo.nFailResult);
                    Messages.SendMixResult(pPlayer, null, 0);
                }
                else
                {
                    pMainCard.m_Instance.nEnhance++;
                    Summon.StageUpped(pMainCard, pMainCard.m_pSummon);
                    pMainCard.m_bIsNeedUpdateToDB = true;
                    Messages.SendItemMessage(pPlayer, pMainCard);
                    uint[] handles = new uint[1];
                    handles[0] = pMainCard.m_hHandle;

                    Messages.SendMixResult(pPlayer, handles, 1);
                    bResult = true;
                    pMainCard.DBQuery(new DB_UpdateItem(pMainCard));
                    ServerLog.Log((ushort)0x96A, pPlayer.GetAccountID(), pPlayer.GetSID(), pMainCard.m_Instance.nLevel + 100 * pMainCard.m_Instance.nEnhance,
                        pMainCard.m_Instance.Code, 1, pMixInfo.id, 0, 0, 0, 0, pMainCard.m_Instance.UID, pPlayer.GetAccountName(), pPlayer.GetName(), "", "SUCS");
                }
            }
            else
            {
                Messages.SendResult(pPlayer, 256, 28, 0);
                return false;
            }
            return bResult;
        }

        
// Function       :   public static bool MixManager::MixItemLevel(const struct MixBase *, struct StructPlayer *, struct StructItem *, int, struct StructItem * *, unsigned short *)
// Function       :   public static bool MixManager::RecycleItem(const struct MixBase *, struct StructPlayer *, struct StructItem *, int, struct StructItem * *, unsigned short *)
// Function       :   public static bool MixManager::RestoreEnhance(const struct MixBase *, struct StructPlayer *, struct StructItem *, int, struct StructItem * *, unsigned short *)

        public static bool CreateItem(MixBase pMixInfo, Player pPlayer, Item pMainMaterial, int nSubMaterialCount, ref Item[] pSubMaterial, ref ushort[] pCountList)
        {
            Item pItem = null;  // 112  70h
            Item pNewItem = null;
            uint hItem;         // 20   14h
            int nItemID;        // 44   2Ch
            long nItemCount;    // 88   58h
            bool bResult;       // 116  119 74h
            int i;              // 112  70h
            int nRandom;

            if (pMainMaterial != null)
            {
                ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pMainMaterial.m_Instance.nLevel + 100 * pMainMaterial.m_Instance.nEnhance,
                    pMainMaterial.m_Instance.Code,1,pMainMaterial.m_Instance.nCount,pMixInfo.id,0,0,0,pMainMaterial.m_Instance.UID,pPlayer.GetAccountName(),
                    pPlayer.GetName(),"","CREATE_ITEM");
                pPlayer.EraseItem(pMainMaterial, pMainMaterial.m_Instance.nCount);
            }

            for(i = 0; i < nSubMaterialCount; ++i)
            {
                ServerLog.Log((ushort)0x969,pPlayer.GetAccountID(),pPlayer.GetSID(),pSubMaterial[i].m_Instance.nLevel + 100 * pSubMaterial[i].m_Instance.nEnhance,
                    pSubMaterial[i].m_Instance.Code,1,pSubMaterial[i].m_Instance.nCount - 1,pMixInfo.id,0,0,0,pSubMaterial[i].m_Instance.UID,
                    pPlayer.GetAccountName(),pPlayer.GetName(),"","CREATE_ITEM");
                pPlayer.EraseItem(pSubMaterial[i], pCountList[i]);
            }
            bResult = false;
            if (pMixInfo.value[2] <= Globals.GetRandomInt32(0, 99))
            {
                ServerLog.Log((ushort)0x96A,pPlayer.GetAccountID(),pPlayer.GetSID(),0,0,0,pMixInfo.id,0,0,0,0,0,pPlayer.GetAccountName(),pPlayer.GetName(),"","FAIL");
                Messages.SendMixResult(pPlayer, null, 0);
            }
            else
            {
                nRandom = Globals.GetRandomInt32(pMixInfo.value[3], pMixInfo.value[4]);
                if (pMixInfo.value[0] < 0 )
                    nItemCount = nRandom;
                else
                    nItemCount = 1;
                if (nItemCount > 0 )
                {
                    bResult = true;
                    while (nItemCount > 0)
                    {
                        nItemID = pMixInfo.value[0];
                        nItemCount = nRandom;
                        while (nItemID < 0 )
                        {
                            GameContent.SelectItemIDFromDropGroup(nItemID, out nItemID, out nItemCount);
                        }
                        pItem = Item.AllocItem(0,nItemID,nItemCount,ItemInstance.GenerateCode.ByMix,pMixInfo.value[1],-1,-1,-1,0,0,0,0,-1,0,0,0,0);

                        if (!pItem.IsJoinable())
                            Messages.PrintfChatMessage(false, 32, "@SYSTEM", pPlayer, "@253\v#@item_name@#\v@{0}", pItem.m_pItemBase.nNameId);
                        else
                            Messages.PrintfChatMessage(false, 32, "@SYSTEM", pPlayer, "@254\v#@item_name@#\v@{0}\v#@item_num@#\v{1}",
                                pItem.m_pItemBase.nNameId,pItem.m_Instance.nCount);

                        pNewItem = pPlayer.PushItem(pItem, pItem.m_Instance.nCount, false);

                        ServerLog.Log((ushort)0x961,pPlayer.GetAccountID(),pPlayer.GetSID(),pNewItem.m_Instance.nLevel + 100 * pNewItem.m_Instance.nEnhance,
                            pNewItem.m_Instance.Code,pItem.m_Instance.nCount,pNewItem.m_Instance.nCount,pPlayer.m_nGold,pPlayer.m_nGold,
                            (long)pPlayer.mv.x,(long)pPlayer.mv.y,0,pPlayer.GetAccountName(),pPlayer.GetName(),"","MIX");

                        if (pItem.m_hHandle != pNewItem.m_hHandle)
                            Item.PendFreeItem(pItem);
                        pNewItem.m_bIsNeedUpdateToDB = true;
                        pNewItem.DBQuery(new DB_UpdateItem(pNewItem));
                        uint[] handles = new uint[1];
                        handles[0] = pNewItem.m_hHandle;
                        Messages.SendMixResult(pPlayer, handles, (uint)pItem.m_Instance.nCount);

                        ServerLog.Log((ushort)0x96A,pPlayer.GetAccountID(),pPlayer.GetSID(),pItem.m_Instance.nLevel + 100 * pItem.m_Instance.nEnhance,
                            pItem.m_Instance.Code,nRandom,pMixInfo.id,0,0,0,0,pItem.m_Instance.UID,pPlayer.GetAccountName(),pPlayer.GetName(),"","SUCS");

                        nItemCount--;
                    }
                }
            }
            return bResult;
        }

// Function       :   public static bool MixManager::SetElementalEffect(const struct MixBase *, struct StructPlayer *, struct StructItem *, int, struct StructItem * *, unsigned short *)
// Function       :   public static bool MixManager::SetElementalEffectParameter(const struct MixBase *, struct StructPlayer *, struct StructItem *, int, struct StructItem * *, unsigned short *)

        public static MixBase GetProperMixInfo(Item pMainMaterial, int nSubMaterialCount, ref Item[] pSubMaterial, ref ushort[] pCountList)
        {
            ushort nCount;                          //-20   -14h

            foreach (MixBase mb in s_vMixInfo)
            {
                if (mb.sub_material_cnt == nSubMaterialCount)
                {
                    nCount = 1;
                    if (check_material_info(mb.main_material, pMainMaterial, ref nCount))
                    {
                        Globals.Log.Info("GetProperMixInfo: Main ID: {0}", mb.id);
                        if (getProperMixInfoSub(mb, nSubMaterialCount, ref pSubMaterial, ref pCountList))
                            return mb;
                    }
                }
            }
            return null;
        }

        public static bool getProperMixInfoSub(MixBase mb, int nSubMaterialCount, ref Item[] pSubMaterial, ref ushort[] pCountList)
        {
            bool[] vCheckInfo = new bool[9];        // 16   -10h

            // so if the main material matches we should loop through and check the sub-materials
            for (int i = 0; i < nSubMaterialCount; ++i)
            {
                bool ok = false;
                for (int j = 0; j < nSubMaterialCount; ++j)
                {
                    if (!vCheckInfo[j])
                    {
                        if (check_material_info(mb.sub_material[j], pSubMaterial[i], ref pCountList[i]))
                        {
                            // we have a match, can keep testing
                            vCheckInfo[j] = true;
                            ok = true;
                            break;
                        }
                    }
                }
                // see if we have a match, if not then we do not match
                if (!ok)
                    return false;
            }
            return true;
        }

        public static void RegisterMixInfo(MixBase info)
        {
            foreach (MixBase mb in s_vMixInfo)
            {
                if(mb.id == info.id)
                    return;
            }
            s_vMixInfo.Add(info);
        }

        public static Item check_mixable_item(Player pPlayer, uint hItem, long nItemCount)
        {

            Item retItem = GameObject.get(hItem) as Item;
            if (retItem == null)
                return null;
            if (!retItem.IsItem())
            {
                Messages.SendResult(pPlayer, 256, 6, 0);
                return null;
            }

            if (retItem.m_Instance.nCount < nItemCount)
            {
                Messages.SendResult(pPlayer, 256, 1, 0);
                return null;
            }
            if ((retItem.m_pItemBase.Flag & 4) != 0)
            {
                Messages.SendResult(pPlayer, 256, 6, 0);
                return null;
            }

            if (!pPlayer.IsMixable(retItem))
            {
                Messages.SendResult(pPlayer, 256, 1, 0);
                retItem = null;
            }
            return retItem;
        }

        public static bool check_material_info(MixBase.MaterialInfo info, Item pItem, ref ushort pItemCount)
        {
            bool result = false;
            bool bIsCountChecked;// = byte ptr -1
            int i;
            int tv;
// .text:005353E5 pItem           = dword ptr  0Ch
// .text:005353E5 pItemCount      = dword ptr  10h

            bIsCountChecked = false;

            if (info.type[0] == 0)
                return pItem == null;

            if (pItem == null)
                return false;

            for (i = 0; i < MixBase.MaterialInfo.MATERIAL_INFO_COUNT; ++i)
            {
                switch (info.type[i])
                {
                    case (int)MixBase.CheckType.ItemGroup:
                        if (pItem.m_pItemBase.nGroup != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ItemClass:
                        if ((int)pItem.m_pItemBase.nClass != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ItemId:
                        if (pItem.m_Instance.Code != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ItemRank:
                        if (pItem.GetItemRank() != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ItemLevel:
                        if (pItem.m_Instance.nLevel != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.FlagOn:
                        if (((1 << (info.value[i] & 0x1F)) & pItem.m_Instance.Flag) == 0)
                            return false;
                        break;

                    case (int)MixBase.CheckType.FlagOff:
                        if(((1 << (info.value[i] & 0x1F)) & pItem.m_Instance.Flag) != 0)
                            return false;
                        break;

                    case (int)MixBase.CheckType.EnhanceMatch:
                        if (pItem.m_Instance.nEnhance != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.EnhanceMismatch:
                        if (pItem.m_Instance.nEnhance == info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ItemCount:
                        bIsCountChecked = true;
                        if (pItemCount != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ElementalEffectMatch:
                        tv = ((int)Math.Pow(2.0,(double)pItem.GetElementalEffectType())) >> 1;
                        if (tv != 0)
                        {
                            if ((tv & info.value[i]) != tv)
                                return false;
                        }
                        else
                        {
                            if (info.value[i] != 0)
                                return false;
                        }
                        break;

                    case (int)MixBase.CheckType.ElementalEffectMismatch:
                        tv = ((int)Math.Pow(2.0, (double)pItem.GetElementalEffectType())) >> 1;
                        if (tv != 0)
                        {
                            if ((tv & info.value[i]) == tv)
                                return false;
                        }
                        else
                        {
                            if (info.value[i] == 0)
                                return false;
                        }
                        break;

                    case (int)MixBase.CheckType.ItemWearPositionMatch:
                        if ((int)pItem.GetWearType() != info.value[i])
                            return false;
                        break;

                    case (int)MixBase.CheckType.ItemWearPositionMismatch:
                        if ((int)pItem.GetWearType() == info.value[i])
                            return false;
                        break;

                }
            }
            if (!bIsCountChecked)
                pItemCount = 1;
            return true;
        }

        public static EnhanceInfo getEnhanceInfo(int sid)
        {
            foreach (EnhanceInfo ei in s_vEnhanceInfo)
            {
                if(ei.nSID == sid)
                    return ei;
            }
            return null;
        }

        public static void procEnhanceFail(Player pPlayer, Item pItem, int nFailResult)
        {
            if (nFailResult == 2 )
            {
                if (pItem.m_Instance.nEnhance <= 3 )
                {
                    pPlayer.EraseItem(pItem, 1);
                    return;
                }
                pItem.m_Instance.nEnhance = pItem.m_Instance.nEnhance - 3;
                pItem.m_bIsNeedUpdateToDB = true;
                pItem.DBQuery(new DB_UpdateItem(pItem));
                Messages.SendItemMessage(pPlayer, pItem);
                return;
            }
            if (nFailResult == 1 )
            {
                pItem.m_Instance.Flag |= 8;
                pItem.m_Instance.Socket[0] = 0;
                pItem.m_Instance.Socket[1] = 0;
                pItem.m_Instance.Socket[2] = 0;
                pItem.m_Instance.Socket[3] = 0;
                pItem.DBQuery(new DB_UpdateItem(pItem));
                Messages.SendItemMessage(pPlayer, pItem);
                return;
            }
            if (nFailResult == 3 )
            {
                pItem.m_bIsNeedUpdateToDB = true;
                if (pItem.m_Instance.nEnhance > 3 )
                    pItem.m_Instance.nEnhance = pItem.m_Instance.nEnhance - 3;
                else
                    pItem.m_Instance.nEnhance = 0;
                Messages.SendItemMessage(pPlayer,pItem);
                pItem.DBQuery(new DB_UpdateItem(pItem));
            }
        }
    }
}
